<?xml version='1.0' encoding='iso-8859-1'?>
<!doctype html public '-//W3C//DTD XHTML 1.0 Strict//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
<html xmlns='http://www.w3c.org/1999/xhtml' lang='en-us'>
	<head>
		<title>
			pev.c
			</title>
		<meta http-equiv='content-type' content='text/html;iso-8859-1'/>
		<meta name='generator' content='motley-tools 1.9.4 13:40:33 Feb 18 2015'/>
		<meta name='author' content='cmaier@cmassoc.net'/>
		<meta name='robots' content='noindex,nofollow'/>
		<link href='toolkit.css' rel='stylesheet' type='text/css'/>
		</head>
	<body>
		<div class='headerlink'>
			[<a href='pcap_nametoindex.c.html' title=' pcap_nametoindex.c '>PREV</a>]
			[<a href='toolkit.html' title=' Index '>HOME</a>]
			[<a href='pev_cm_atten_char.c.html' title=' pev_cm_atten_char.c '>NEXT</a>]
			</div>
<pre>
/*====================================================================*
 *
 *   Copyright (c) 2013 Qualcomm Atheros, Inc.
 *
 *   All rights reserved.
 *
 *   Redistribution and use in source and binary forms, with or 
 *   without modification, are permitted (subject to the limitations 
 *   in the disclaimer below) provided that the following conditions 
 *   are met:
 *
 *   * Redistributions of source code must retain the above copyright 
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above 
 *     copyright notice, this list of conditions and the following 
 *     disclaimer in the documentation and/or other materials 
 *     provided with the distribution.
 *
 *   * Neither the name of Qualcomm Atheros nor the names of 
 *     its contributors may be used to endorse or promote products 
 *     derived from this software without specific prior written 
 *     permission.
 *
 *   NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE 
 *   GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE 
 *   COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; AND ANY EXPRESS OR 
 *   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 *   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 *   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
 *   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 *   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 *   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 *   OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  
 *
 *--------------------------------------------------------------------*/

/*====================================================================*
 *
 *   pev.c - QCA Plug-in Electric Vehicle Emulator;
 *
 *   This program, in the current state, is not a finished product;
 *   It has been released so that interested parties can begin to 
 *   see how the SLAC protocol might be implemented;
 *
 *   Some key design features are:
 *
 *   1) the use of a channel variable to abstract ISO Layer 2 I/O;
 *      the variable is used by functions openchannel, readmessage,
 *      sendmessage and closechannel;
 *
 *   2) the use of a message variable to represent an IEEE 802.3 
 *      Ethernet frame; the variable allows one frame to be used
 *      and re-used throughout the program but supports multiple
 *      frame buffers if needed;
 *
 *   3) the use of a session variable to support multiple PEV-EVSE
 *      interactions without using threads or subrocesses; this has
 *      not demonstrated in this version of the program; some more
 *      work is needed;
 *
 *   4) the absence of threads or subprocesses so that the  program 
 *      can be ported to hosts without a multi-tasking operating 
 *      system;
 *
 *   5) lots of debugging messages; these can be suppressed or 
 *      deleted if not wanted;
 *
 *   6) simplified state machine;
 *
 *--------------------------------------------------------------------*/

/*====================================================================*
 *   system header files;
 *--------------------------------------------------------------------*/

#include &lt;unistd.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;limits.h&gt;
#include &lt;string.h&gt;
#include &lt;errno.h&gt;
#include &lt;time.h&gt;

/*====================================================================*
 *   custom header files;
 *--------------------------------------------------------------------*/

#include &quot;../tools/getoptv.h&quot;
#include &quot;../tools/putoptv.h&quot;
#include &quot;../tools/memory.h&quot;
#include &quot;../tools/number.h&quot;
#include &quot;../tools/types.h&quot;
#include &quot;../tools/flags.h&quot;
#include &quot;../tools/files.h&quot;
#include &quot;../tools/error.h&quot;
#include &quot;../tools/config.h&quot;
#include &quot;../ether/channel.h&quot;
#include &quot;../iso15118/slac.h&quot;

/*====================================================================*
 *   custom source files;
 *--------------------------------------------------------------------*/

#ifndef MAKEFILE
#include &quot;../tools/getoptv.c&quot;
#include &quot;../tools/putoptv.c&quot;
#include &quot;../tools/version.c&quot;
#include &quot;../tools/hexdump.c&quot;
#include &quot;../tools/hexdecode.c&quot;
#include &quot;../tools/hexencode.c&quot;
#include &quot;../tools/hexstring.c&quot;
#include &quot;../tools/decdecode.c&quot;
#include &quot;../tools/decstring.c&quot;
#include &quot;../tools/uintspec.c&quot;
#include &quot;../tools/todigit.c&quot;
#include &quot;../tools/strfbits.c&quot;
#include &quot;../tools/config.c&quot;
#include &quot;../tools/memincr.c&quot;
#include &quot;../tools/error.c&quot;
#endif

#ifndef MAKEFILE
#include &quot;../plc/Devices.c&quot;
#endif

#ifndef MAKEFILE
#include &quot;../mme/EthernetHeader.c&quot;
#include &quot;../mme/QualcommHeader.c&quot;
#include &quot;../mme/HomePlugHeader1.c&quot;
#include &quot;../mme/UnwantedMessage.c&quot;
#include &quot;../mme/readmessage.c&quot;
#include &quot;../mme/sendmessage.c&quot;
#endif

#ifndef MAKEFILE
#include &quot;../ether/channel.c&quot;
#include &quot;../ether/openchannel.c&quot;
#include &quot;../ether/closechannel.c&quot;
#include &quot;../ether/sendpacket.c&quot;
#include &quot;../ether/readpacket.c&quot;
#endif

#ifndef MAKEFILE
#include &quot;../iso15118/slac_session.c&quot;
#include &quot;../iso15118/slac_connect.c&quot;
#include &quot;../iso15118/slac_debug.c&quot;
#include &quot;../iso15118/pev_cm_slac_param.c&quot;
#include &quot;../iso15118/pev_cm_start_atten_char.c&quot;
#include &quot;../iso15118/pev_cm_atten_char.c&quot;
#include &quot;../iso15118/pev_cm_mnbc_sound.c&quot;
#include &quot;../iso15118/pev_cm_slac_match.c&quot;
#include &quot;../iso15118/pev_cm_set_key.c&quot;
#endif

/*====================================================================*
 *   program constants;
 *--------------------------------------------------------------------*/

#define PLCDEVICE &quot;PLC&quot;
#define PROFILE &quot;pev.ini&quot;
#define SECTION &quot;default&quot;   

#define PEV_STATE_DISCONNECTED 1
#define PEV_STATE_UNMATCHED 2
#define PEV_STATE_MATCHED 3

#define PEV_VID &quot;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&quot; // VehicleIdentifier
#define PEV_NMK &quot;50D3E4933F855B7040784DF815AA8DB7&quot;   // HomePlugAV
#define PEV_NID &quot;B0F2E695666B03&quot;		     // HomePlugAV

/*====================================================================*
 *   program variables;
 *--------------------------------------------------------------------*/

unsigned state = 0; 

/*====================================================================*
 *
 *   static void configure ();
 *
 *   print template PEV-HLE configuration file on stdout so that 
 *   profile, section and element names match;
 *
 *--------------------------------------------------------------------*/

static void configure () 

{ 
	printf (&quot;# file: %s\n&quot;, PROFILE); 
	printf (&quot;# ====================================================================\n&quot;); 
	printf (&quot;# PEV-HLE initialization;\n&quot;); 
	printf (&quot;# --------------------------------------------------------------------\n&quot;); 
	printf (&quot;[%s]\n&quot;, SECTION); 
	printf (&quot;vehicle identifier = %s\n&quot;, PEV_VID); 
	printf (&quot;network membership key = %s\n&quot;, PEV_NMK); 
	printf (&quot;network identifier = %s\n&quot;, PEV_NID); 
	printf (&quot;attenuation threshold = %d\n&quot;, SLAC_LIMIT); 
	printf (&quot;msound pause = %d\n&quot;, SLAC_PAUSE); 
	printf (&quot;charge time = %d\n&quot;, SLAC_CHARGETIME); 
	printf (&quot;settle time = %d\n&quot;, SLAC_SETTLETIME); 
	return; 
} 

/*====================================================================*
 *
 *   void initialize (struct session * session, char const * profile, char const * section);
 *
 *   read PEV-HLE configuration profile; initialize session variable;
 *
 *--------------------------------------------------------------------*/

static void initialize (struct session * session, char const * profile, char const * section) 

{ 
	session-&gt;next = session-&gt;prev = session; 
	hexencode (session-&gt;PEV_ID, sizeof (session-&gt;PEV_ID), configstring (profile, section, &quot;VehicleIdentifier&quot;, PEV_VID)); 
	hexencode (session-&gt;NMK, sizeof (session-&gt;NMK), configstring (profile, section, &quot;NetworkMembershipKey&quot;, PEV_NMK)); 
	hexencode (session-&gt;NID, sizeof (session-&gt;NID), configstring (profile, section, &quot;NetworkIdentifier&quot;, PEV_NID)); 
	session-&gt;limit = confignumber_range (profile, section, &quot;AttenuationThreshold&quot;, SLAC_LIMIT, 0, UINT_MAX); 
	session-&gt;pause = confignumber_range (profile, section, &quot;MSoundPause&quot;, SLAC_PAUSE, 0, UINT_MAX); 
	session-&gt;settletime = confignumber_range (profile, section, &quot;SettleTime&quot;, SLAC_SETTLETIME, 0, UINT_MAX); 
	session-&gt;chargetime = confignumber_range (profile, section, &quot;ChargeTime&quot;, SLAC_CHARGETIME, 0, UINT_MAX); 
	session-&gt;state = PEV_STATE_DISCONNECTED; 
	memcpy (session-&gt;original_nmk, session-&gt;NMK, sizeof (session-&gt;original_nmk)); 
	memcpy (session-&gt;original_nid, session-&gt;NID, sizeof (session-&gt;original_nid)); 
	slac_session (session); 
	return; 
} 

/*====================================================================*
 *
 *   signed identifier (struct session * session, struct channel * channel);
 *
 *   generate the run identifier and store in session variable;
 *
 *   copy channel host address to session PEV MAC address; set session
 *   PEV identifier to zeros;
 *
 *--------------------------------------------------------------------*/

static signed identifier (struct session * session, struct channel * channel) 

{ 
	time_t now; 
	time (&amp; now); 
	memset (session-&gt;RunID, 0, sizeof (session-&gt;RunID)); 
	memcpy (session-&gt;RunID, channel-&gt;host, ETHER_ADDR_LEN); 
	memcpy (session-&gt;PEV_MAC, channel-&gt;host, sizeof (session-&gt;PEV_MAC)); 
	return (0); 
} 

/*====================================================================*
 *
 *   void DisconnectedState (struct session * session, struct channel * channel, struct message * message);
 *
 *--------------------------------------------------------------------*/

static void DisconnectedState (struct session * session, struct channel * channel, struct message * message) 

{ 
	slac_session (session); 
	slac_debug (session, 0, __func__, &quot;Probing ...&quot;); 
	memincr (session-&gt;RunID, sizeof (session-&gt;RunID)); 
	while (pev_cm_slac_param (session, channel, message)); 
	session-&gt;state = PEV_STATE_UNMATCHED; 
	return; 
} 

/*====================================================================*
 *
 *   void MatchingState (struct session * session, struct channel * channel, struct message * message);
 *
 *   The PEV-EVSE perform GreenPPEA protocol in this state;
 *
 *   the cm_start_atten_char and cm_mnbc_sound messages are sent
 *   broadcast; the application may receive multiple cm_atten_char
 *   messages before sending the cm_slac_match message;
 *
 *--------------------------------------------------------------------*/

static void UnmatchedState (struct session * session, struct channel * channel, struct message * message) 

{ 
	slac_session (session); 
	slac_debug (session, 0, __func__, &quot;Sounding ...&quot;); 
	if (pev_cm_start_atten_char (session, channel, message)) 
	{ 
		session-&gt;state = PEV_STATE_DISCONNECTED; 
		return; 
	} 
	if (pev_cm_mnbc_sound (session, channel, message)) 
	{ 
		session-&gt;state = PEV_STATE_DISCONNECTED; 
		return; 
	} 
	if (pev_cm_atten_char (session, channel, message)) 
	{ 
		session-&gt;state = PEV_STATE_DISCONNECTED; 
		return; 
	} 
	if (slac_connect (session)) 
	{ 
		session-&gt;state = PEV_STATE_DISCONNECTED; 
		return; 
	} 
	slac_debug (session, 0, __func__, &quot;Matching ...&quot;); 
	if (pev_cm_slac_match (session, channel, message)) 
	{ 
		session-&gt;state = PEV_STATE_DISCONNECTED; 
		return; 
	} 
	session-&gt;state = PEV_STATE_MATCHED; 
	return; 
} 

/*====================================================================*
 *
 *   void MatchedState (struct session * session, struct channel * channel, struct message * message);
 *
 *   charge vehicle; restore original NMK/NID and disconnect; loop
 *   if SLAC_CONTINUE is set;
 *
 *--------------------------------------------------------------------*/

static void MatchedState (struct session * session, struct channel * channel, struct message * message) 

{ 
	slac_session (session); 
	slac_debug (session, 0, __func__, &quot;Connecting ...&quot;); 

#if SLAC_AVLN_EVSE

	slac_debug (session, 0, __func__, &quot;waiting for evse to settle ...&quot;); 
	sleep (session-&gt;settletime); 

#endif
#if SLAC_AVLN_PEV

	if (pev_cm_set_key (session, channel, message)) 
	{ 
		session-&gt;state = PEV_STATE_DISCONNECTED; 
		return; 
	} 
	sleep (session-&gt;settletime); 

#endif

	slac_debug (session, 0, __func__, &quot;Charging (%d) ...\n\n&quot;, session-&gt;counter++); 
	sleep (session-&gt;chargetime); 
	slac_debug (session, 0, __func__, &quot;Disconnecting ...&quot;); 

#if SLAC_AVLN_EVSE

	slac_debug (session, 0, __func__, &quot;waiting for evse to settle ...&quot;); 
	sleep (session-&gt;settletime); 

#endif

#if SLAC_AVLN_PEV

	memcpy (session-&gt;NMK, session-&gt;original_nmk, sizeof (session-&gt;NMK)); 
	memcpy (session-&gt;NID, session-&gt;original_nid, sizeof (session-&gt;NID)); 
	if (pev_cm_set_key (session, channel, message)) 
	{ 
		session-&gt;state = PEV_STATE_DISCONNECTED; 
		return; 
	} 
	sleep (session-&gt;settletime); 

#endif

	session-&gt;state = state; 
	return; 
} 

/*====================================================================*
 *   
 *   int main (int argc, char * argv[]);
 *   
 *
 *--------------------------------------------------------------------*/

int main (int argc, char const * argv []) 

{ 
	extern struct channel channel; 
	static char const * optv [] = 
	{ 
		&quot;cCdi:lp:qs:t:vx&quot;, 
		&quot;&quot;, 
		&quot;Plug-in Electric Vehicle Emulator&quot;, 
		&quot;c\tprint template configuration file on stdout&quot;, 
		&quot;C\tstop on count mismatch&quot;, 
		&quot;d\tdisplay debug information&quot;, 

#if defined (WINPCAP) || defined (LIBPCAP)

		&quot;i n\thost interface is (n) [&quot; LITERAL (CHANNEL_ETHNUMBER) &quot;]&quot;, 

#else

		&quot;i s\thost interface is (s) [&quot; LITERAL (CHANNEL_ETHDEVICE) &quot;]&quot;, 

#endif

		&quot;l\tloop indefinitely&quot;, 
		&quot;p s\tconfiguration profile is (s) [&quot; LITERAL (PROFILE) &quot;]&quot;, 
		&quot;q\tsuppress normal output&quot;, 
		&quot;s s\tconfiguration section is (s) [&quot; LITERAL (SECTION) &quot;]&quot;, 
		&quot;t n\tread timeout is (n) milliseconds [&quot; LITERAL (SLAC_TIMEOUT) &quot;]&quot;, 
		&quot;v\tverbose messages on stdout&quot;, 
		&quot;x\texit on error&quot;, 
		(char const *) (0)
	}; 
	struct session session; 
	struct message message; 
	char const * profile = PROFILE; 
	char const * section = SECTION; 
	signed c; 
	memset (&amp; session, 0, sizeof (session)); 
	memset (&amp; message, 0, sizeof (message)); 
	channel.timeout = SLAC_TIMEOUT; 
	if (getenv (PLCDEVICE)) 
	{ 

#if defined (WINPCAP) || defined (LIBPCAP)

		channel.ifindex = atoi (getenv (PLCDEVICE)); 

#else

		channel.ifname = strdup (getenv (PLCDEVICE)); 

#endif

	} 
	optind = 1; 
	while (~ (c = getoptv (argc, argv, optv))) 
	{ 
		switch (c) 
		{ 
		case 'c': 
			configure (); 
			return (0); 
		case 'C': 
			_setbits (session.flags, SLAC_COMPARE); 
			break; 
		case 'd': 
			_setbits (session.flags, (SLAC_VERBOSE | SLAC_SESSION)); 
			break; 
		case 'i': 

#if defined (WINPCAP) || defined (LIBPCAP)

			channel.ifindex = atoi (optarg); 

#else

			channel.ifname = optarg; 

#endif

			break; 
		case 'l': 
			state = PEV_STATE_DISCONNECTED; 
			break; 
		case 'p': 
			profile = optarg; 
			break; 
		case 's': 
			section = optarg; 
			break; 
		case 'q': 
			_setbits (channel.flags, CHANNEL_SILENCE);
			_setbits (session.flags, SLAC_SILENCE);
			break; 
		case 't': 
			channel.timeout = (unsigned) (uintspec (optarg, 0, UINT_MAX)); 
			break; 
		case 'v': 
			_setbits (channel.flags, CHANNEL_VERBOSE); 
			break; 
		case 'x': 
			session.exit = session.exit? 0: 1; 
			break; 
		default: 
			break; 
		} 
	} 
	argc -= optind; 
	argv += optind; 
	if (argc) 
	{ 
		slac_debug (&amp; session, 1, __func__, ERROR_TOOMANY); 
	} 
	openchannel (&amp; channel); 
	identifier (&amp; session, &amp; channel); 
	initialize (&amp; session, profile, section); 
	if (pev_cm_set_key (&amp; session, &amp; channel, &amp; message)) 
	{ 
		slac_debug (&amp; session, 1, __func__, &quot;Can't set key&quot;); 
	} 
	sleep (session.settletime); 
	while (session.state) 
	{ 
		if (session.state == PEV_STATE_DISCONNECTED) 
		{ 
			DisconnectedState (&amp; session, &amp; channel, &amp; message); 
			continue; 
		} 
		if (session.state == PEV_STATE_UNMATCHED) 
		{ 
			UnmatchedState (&amp; session, &amp; channel, &amp; message); 
			continue; 
		} 
		if (session.state == PEV_STATE_MATCHED) 
		{ 
			MatchedState (&amp; session, &amp; channel, &amp; message); 
			continue; 
		} 
		slac_debug (&amp; session, 1, __func__, &quot;Illegal state!&quot;); 
	} 
	closechannel (&amp; channel); 
	return (0); 
} 


</pre>
		<div class='footerlink'>
			[<a href='pcap_nametoindex.c.html' title=' pcap_nametoindex.c '>PREV</a>]
			[<a href='toolkit.html' title=' Index '>HOME</a>]
			[<a href='pev_cm_atten_char.c.html' title=' pev_cm_atten_char.c '>NEXT</a>]
			</div>
		</body>
	</html>
